using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework;
using Xyne.Utilities;
using Xyne.Events;
using Xyne.Actions;

namespace Xyne.Network
{
    public class ServerComponent : NetworkComponent
    {
        private PacketReader reader;

        public ServerComponent(Game game) : base(game)
        {
            Wizard = GameObjects.LeftWizard;
            reader = new PacketReader();
        }

        /// <summary>
        /// The bottleneck where all network-based events go (i.e. game ending)
        /// </summary>
        /// <param name="e">The event</param>
        public override void HandleEvent(Event e)
        {
            if (e is GameQuitEvent)
            {
                GameQuitEvent over = e as GameQuitEvent;

                DataQueue.Enqueue(over);

                EventManager.Instance.SendEvent(e);
            }
            else if (e is GamePauseEvent)
            {
                GamePauseEvent pause = e as GamePauseEvent;

                DataQueue.Enqueue(pause);

                EventManager.Instance.SendEvent(e);
            }
            else if (e is GameWonEvent)
            {
                GameWonEvent won = e as GameWonEvent;

                // I won, let the client knows that he/she has lost
                DataQueue.Enqueue(won.SwitchContext());

                EventManager.Instance.SendEvent(e);
            }
            else if (e is GameLostEvent)
            {
                GameLostEvent lost = e as GameLostEvent;

                // I lost, let the client knows that he/she has won
                DataQueue.Enqueue(lost.SwitchContext());

                EventManager.Instance.SendEvent(e);
            }
            else
            {
                // Default to local event handling
                EventManager.Instance.SendEvent(e);
            }
        }

        /// <summary>
        /// The bottleneck where all network-based actions go (i.e. game fireball)
        /// </summary>
        /// <param name="e">The action</param>
        public override void HandleAction(Action a)
        {
            ActionManager.Instance.ActionActivated(a);
        }

        public void CreateLobby()
        {
            if (Session != null && Session.IsDisposed)
            {
                Session = null;
            }

            if (Session == null)
            {
                Session = NetworkSession.Create(ConnectionType, 1, 2);
                Session.AllowHostMigration = false;
                Session.AllowJoinInProgress = false;

                if (Session.LocalGamers.Count > 0)
                    Gamer = Session.LocalGamers[0];
            }
        }

        public override void Update(GameTime gameTime)
        {
            // Queue the game state, piped string for now (bleh!)
            if (StateEntities.Count > 0)
            {
                GameStateData gameState = new GameStateData(StateEntities);
                DataQueue.Enqueue(gameState);
            }

            base.Update(gameTime);

            if (Session != null && Gamer != null)
            {
                while (Gamer.IsDataAvailable)
                {
                    NetworkGamer sender;
                    Gamer.ReceiveData(reader, out sender);

                    if (!sender.IsLocal)
                    {
                        while (reader.PeekChar() != -1)
                        {
                            ulong type = reader.ReadUInt64();
                            if (type != 0)
                            {
                                String gamer = reader.ReadString(); // The player that this came from

                                switch ((NetworkDataType)type)
                                {
                                    case NetworkDataType.GameQuit:
                                        EventManager.Instance.SendEvent(new GameQuitEvent(this, gamer));
                                        DataQueue.Enqueue(new GameQuitEvent(this, gamer));
                                        break;
                                    case NetworkDataType.GamePause:
                                        GamePauseEvent pause = GamePauseEvent.Deserialize(reader);
                                        EventManager.Instance.SendEvent(pause);
                                        DataQueue.Enqueue(pause);
                                        break;
                                    case NetworkDataType.GameLost:
                                        // Enemy lost, return to player and notify that I won
                                        GameLostEvent e = GameLostEvent.Deserialize(reader);
                                        EventManager.Instance.SendEvent(e.SwitchContext());
                                        DataQueue.Enqueue(e);
                                        break;
                                    case NetworkDataType.StartCasting:
                                        // Enemy started to cast
                                        StartCastingEvent startEvent = new StartCastingEvent(this);
                                        startEvent.Gamer = gamer;
                                        EventManager.Instance.SendEvent(startEvent);
                                        break;
                                    case NetworkDataType.StopCasting:
                                        // Enemy stopped casting
                                        StopCastingEvent stopEvent = new StopCastingEvent(this);
                                        stopEvent.Gamer = gamer;
                                        EventManager.Instance.SendEvent(stopEvent);
                                        break;
                                    case NetworkDataType.Action:
                                        Action action = Action.ReadActionFromNetwork(reader);
                                        if (action != null)
                                            ActionManager.Instance.ActionActivated(action);
                                        break;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
